package cn.wolfcode.wolf2w.service.impl;

import cn.wolfcode.wolf2w.domain.*;
import cn.wolfcode.wolf2w.query.StrategyQueryObject;
import cn.wolfcode.wolf2w.redis.service.IRedisService;
import cn.wolfcode.wolf2w.redis.test.RedisByKey;
import cn.wolfcode.wolf2w.repository.StrategyRepository;
import cn.wolfcode.wolf2w.service.*;
import cn.wolfcode.wolf2w.util.DBHelper;
import cn.wolfcode.wolf2w.util.DateUtil;
import cn.wolfcode.wolf2w.util.StrategyStatisVO;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class StrategyServiceImpl implements IStrategyService {

    @Autowired
    private StrategyRepository strategyRepository;
    @Autowired
    private IRedisService redisService;
    @Autowired
    private IRegionService regionService;

    @Autowired
    private IDestinationService destinationService;

    @Autowired
    private IStrategyCatalogService strategyCatalogService;

    @Autowired
    private IStrategyThemeService strategyThemeService;

    @Autowired
    private MongoTemplate template;

    @Autowired
    private StringRedisTemplate template1;

    @Override
    public void insert(Strategy strategy) {
        strategyRepository.insert(strategy);
        strategy.setId(null);
    }

    @Override
    public void delete(String id) {
        strategyRepository.deleteById(id);
    }

    @Override
    public void update(Strategy strategy) {
        strategyRepository.save(strategy);
    }

    @Override
    public Strategy selectOne(String id) {
        Strategy strategy = strategyRepository.findById(id).orElse(null);
        //Strategy strategy = byId.get();
        return strategy;
    }

    @Override
    public List<Strategy> selectAll() {
        List<Strategy> all = strategyRepository.findAll();
        return all;
    }

    //@Override
    //public List<Strategy> getDestByRegionId(String rid) {
    //    //1、通过区域id查询区域对象
    //    Region region = regionService.selectOne(rid);
    //    //2、从区域对象上获取目的地id的集合
    //    List<String> refIds = region.getRefIds();
    //    //3、将目的地id的集合转换成目的地名称的集合
    //    List<Strategy> strategys = strategyRepository.findByIdIn(refIds);
    //    return strategys;
    //}

    @Override
    public Page<Strategy> query(StrategyQueryObject q) {
        //1、创建查询对象
        Query query=new Query();
        if(StringUtils.hasLength(q.getDestId())){
            query.addCriteria(Criteria.where("destId").regex(q.getDestId()));//进行拼接高级查询条件时需要使用regex
        }
        //2、判断keyword是否为空，若不为空，则进行条件的拼接
        if(StringUtils.hasLength(q.getKeyword())){
            query.addCriteria(Criteria.where("name").regex(q.getKeyword()));//进行拼接高级查询条件时需要使用regex
        }
        //判断父亲id长度是否为空，若为空，拼接成null
        if(!StringUtils.hasLength(q.getParentId())){
            query.addCriteria(Criteria.where("parentId").is(null));
        }else{
            query.addCriteria(Criteria.where("parentId").is(q.getParentId()));
        }
        //3、添加分页语句
        Pageable pageable = PageRequest.of(q.getCurrentPage()-1, q.getPageSize(), Sort.Direction.DESC, "_id");
        Page<Strategy> page = DBHelper.query(q,query, Strategy.class, template, pageable);
        return page;
    }

    @Override
    public void saveOrUpdate(Strategy strategy) {
        //通过分类id去找分类名
        String catalogId = strategy.getCatalogId();
        StrategyCatalog strategyCatalog = strategyCatalogService.selectOne(catalogId);
        strategy.setCatalogName(strategyCatalog.getName());
        //通过主题id去找主题名
        String themeId = strategy.getThemeId();
        StrategyTheme strategyTheme = strategyThemeService.selectOne(themeId);
        strategy.setThemeName(strategyTheme.getName());
        //还需要维护一些保存页面没有的字段信息
        //目的地id
        strategy.setDestId(strategyCatalog.getDestId());
        //目的地名称
        strategy.setDestName(strategyCatalog.getName());
        //还需判断是否是国内(通过吐司来进行判断)
        List<Destination> destinations = destinationService.queryToasts(strategyCatalog.getDestId());
        //判断该集合中第一位是否是中国，若是中国，就设置为是国内，反之，则不是
        Destination destination = destinations.get(0);
        String name = destination.getName();
        if("中国".equals(name)){
            strategy.setIsabroad(Strategy.ABROAD_YES);
        }else{
            strategy.setIsabroad(Strategy.ABROAD_NO);
        }
        if(StringUtils.hasLength(strategy.getId())){
            //查询
            Strategy strategy1 = this.selectOne(strategy.getId());
            //设置
            strategy.setViewnum(strategy1.getViewnum());
            strategy.setReplynum(strategy1.getReplynum());
            strategy.setFavornum(strategy1.getFavornum());
            strategy.setSharenum(strategy1.getSharenum());
            strategy.setThumbsupnum(strategy1.getThumbsupnum());
            this.update(strategy);
        }else {
            //在保存之前设置创造时间
            strategy.setCreateTime(new Date());
            this.insert(strategy);
        }
    }

    @Override
    public List<Strategy> queryByCatalogId(String id) {
        List<Strategy> strategies=strategyRepository.queryByCatalogId(id);
        return strategies;
    }

    @Override
    public List<Strategy> queryByThree(String destId) {
        Pageable pageable=PageRequest.of(0, 3, Sort.Direction.DESC,"_id");
        List<Strategy> strategies=strategyRepository.queryByDestId(pageable,destId);
        return strategies;
    }

    @Override
    public List<Strategy> queryByStrategy(String destId) {
        List<Strategy> strategies=strategyRepository.queryByDestId(destId);
        return strategies;
    }

    @Override
    public void viewnum(Strategy strategy) { ;
        //判断redis中是否还有该key，若有将key所对应的键值转成统计数据封装类的类型
        StrategyStatisVO strategyStatisVO1 = this.getStrategyStatisVO(strategy);
        //从该类中取出阅读数
        int viewnum = strategyStatisVO1.getViewnum();
        //加一再封装到该类中
        strategyStatisVO1.setViewnum(viewnum+1);
        //储存到redis中去
        this.setStrategyStatisVO(strategy,strategyStatisVO1);
    }

    @Override
    public StrategyStatisVO getStrategyStatisVO(Strategy strategy) {
        //将传过来的攻略id进行key的拼接
        String key = RedisByKey.STRATEGY_STATIC_VO.join(strategy.getId());
        StrategyStatisVO vo=new StrategyStatisVO();
        //判断redis中是否还有该key，若有将key所对应的键值转成统计数据封装类的类型
        if(template1.hasKey(key)){
            String s = template1.opsForValue().get(key);
            vo = JSON.parseObject(s, StrategyStatisVO.class);
        }else{

            //若redis中不含有该key，我们需要对统计的数值进行初始化
            //对vo对象的字段进行维护
            BeanUtils.copyProperties(strategy, vo);
            //还需要对vo对象中的攻略id字段进行维护
            vo.setStrategyId(strategy.getId());
            this.setStrategyStatisVO(strategy, vo);
        }
        return vo;
    }


    @Override
    public void setStrategyStatisVO(Strategy strategy,StrategyStatisVO strategyStatisVO) {
        ////通过攻略id拼接成key
        String key = RedisByKey.STRATEGY_STATIC_VO.join(strategy.getId());
        //将该类转化成json字符串的格式
        String strategyStatisVo2 = JSON.toJSONString(strategyStatisVO);
        //进行更新
        template1.opsForValue().set(key, strategyStatisVo2);
    }

    @Override
    public void replyNum(Strategy strategy) {
        StrategyStatisVO strategyStatisVO = this.getStrategyStatisVO(strategy);
        strategyStatisVO.setReplynum(strategyStatisVO.getReplynum()+1);
        this.setStrategyStatisVO(strategy,strategyStatisVO );
    }

    @Override
    public boolean favorNum(String sid,String userId) {
        Strategy strategy = this.selectOne(sid);
        //通过userId来拼接key，value为储存的是封装该用户收藏攻略的id集合
        String key = RedisByKey.STRATEGY_USERID_FAVOR.join(userId);
        //判断redis中是否存在该key，若不存在，进行初始化
        List<String> list=new ArrayList<>();
        StrategyStatisVO vo =new StrategyStatisVO();
        //若存在，判断list集合中是否有该攻略id
        if(template1.hasKey(key)){
            //获取value值中储存的集合
            String s = template1.opsForValue().get(key);
            //将字符串形式的集合转成List
            list = JSON.parseArray(s, String.class);
            //判断redis中是否含有攻略id
            if(list.contains(sid)){
                //若该集合中包含sid，获取vo对象，将收藏数减一，移除list中的sid
                //获取vo对象
                vo = this.getStrategyStatisVO(strategy);
                vo.setFavornum(vo.getFavornum()-1);
                list.remove(sid);
            }else{
                //若该集合中不包含sid，则获取vo对象，将收藏数加一，向list中加入sid
                vo=this.getStrategyStatisVO(strategy);
                vo.setFavornum(vo.getFavornum()+1);
                list.add(sid);
            }
        }
        //更新sid集合
        String list1 = JSON.toJSONString(list);
        template1.opsForValue().set(key,list1);
        //更新vo对象
        this.setStrategyStatisVO(strategy, vo);
        return list.contains(sid);
    }

    @Override
    public boolean strategyThumbup(String sid, String userId) {
        Strategy strategy = this.selectOne(sid);
        //用sid和userId来拼接key
        String key = RedisByKey.STRATEGY_HUMBUP.join(sid, userId);
        //判断该key是否存在
        if(!template1.hasKey(key)){
            //若不存在，取出vo对象，将vo对象中的点赞数加一，将该key对应的键值对存入redis中去，并且设置key的有效时间
            StrategyStatisVO vo = this.getStrategyStatisVO(strategy);
            vo.setThumbsupnum(vo.getThumbsupnum()+1);
            //算出有效时间
            Date date = new Date();
            long dateBetween = DateUtil.getDateBetween(date, DateUtil.getEndDate(date));
            template1.opsForValue().set(key, "111",dateBetween, TimeUnit.SECONDS);
            //更新vo对象
            this.setStrategyStatisVO(strategy, vo);
            return true;
        }
        return false;
    }

    @Override
    public void updateStrategyVo(StrategyStatisVO vo) {
        Query query=new Query();
        query.addCriteria(Criteria.where("_id").is(vo.getStrategyId()));
        Update update=new Update();
        update.set("favornum", vo.getFavornum());
        update.set("replynum", vo.getReplynum());
        update.set("strategyId",vo.getStrategyId());
        update.set("sharenum",vo.getSharenum());
        update.set("viewnum", vo.getViewnum());
        update.set("thumbsupnum", vo.getThumbsupnum());
        template.updateMulti(query, update, Strategy.class);
    }

    @Override
    public List<Strategy> queryByDestName(String name) {
        List<Strategy> strategies=strategyRepository.queryByDestName(name);
        return strategies;
    }
}
